﻿using System;
using System.Configuration;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Web;

using Cookbook.Common;

using Microsoft.Practices.EnterpriseLibrary.Logging;

namespace Cookbook.Services.Core.Common
{
    public class EntLibLogger : ILogger
    {
        private const string GeneralCategory = "General";

        #region ILogger Members

        public void Information(string formattedMessage, params object[] arguments)
        {
            WriteEntry(TraceEventType.Information, formattedMessage, arguments);
        }

        public void Warning(string formattedMessage, params object[] arguments)
        {
            WriteEntry(TraceEventType.Warning, formattedMessage, arguments);
        }

        public void Error(string formattedMessage, params object[] arguments)
        {
            WriteEntry(TraceEventType.Error, formattedMessage, arguments);
        }

        public void Error(Exception exception)
        {
            var builder = GetExceptionText(exception);

            Error(builder.ToString());
        }

        public void Error(Exception exception, string errorReference)
        {
            var builder = GetExceptionText(exception);

            builder.AppendLine(string.Format("An internal error has occured ( Code {0})", errorReference));

            Error(builder.ToString());
        }

        public void Verbose(string formattedMessage, params object[] arguments)
        {
            WriteEntry(TraceEventType.Verbose, formattedMessage, arguments);
        }

        public void Critical(string formattedMessage, params object[] arguments)
        {
            WriteEntry(TraceEventType.Critical, formattedMessage, arguments);
        }

        public void Critical(Exception exception)
        {
            var builder = GetExceptionText(exception);

            Critical(builder.ToString());
        }

        public void Critical(Exception exception, string errorReference)
        {
            var builder = GetExceptionText(exception);

            builder.AppendLine(string.Format("An internal error has occured ( Code {0})", errorReference));

            Critical(builder.ToString());
        }

        #endregion

        private static StringBuilder GetExceptionText(Exception exception)
        {
            string[] processDump = ExceptionHelper.GenerateProcessDump(exception, "Server");

            var builder = new StringBuilder();
            foreach (string line in processDump)
            {
                builder.AppendLine(line);
            }
            return builder;
        }

        private static void WriteEntry(TraceEventType severity, string formattedMessage, params object[] arguments)
        {
            SanitizeNullArguments(arguments);

            var entry = new LogEntry
            {
                Message = string.Format(formattedMessage, arguments),
                Severity = severity,
                // force the (lazy) TimeStamp to be set here, otherwise it will be set when it is actualy written to the log
                TimeStamp = DateTime.UtcNow
            };

            entry.Categories.Add(GeneralCategory);

            PrincipleHelper.EnsureCurrentPrincipal();

            entry.ExtendedProperties["sessionId"] = (((HttpContext.Current != null) &&
                (HttpContext.Current.Session != null))
                ? HttpContext.Current.Session.SessionID
                : "");
            entry.ExtendedProperties["user"] = Thread.CurrentPrincipal.Identity.Name;
            entry.ExtendedProperties["applicationName"] = ConfigurationManager.AppSettings["LoggingApplicationName"];

            Logger.Write(entry);
        }

        private static void SanitizeNullArguments(object[] arguments)
        {
            for (int i = 0; i < arguments.Length; i++)
            {
                if (arguments[i] == null)
                {
                    arguments[i] = "null";
                }
            }
        }
    }
}